<template>
  <div class="edit-table">
    <el-button
      type="success"
      plain
      style="margin-top: 12px; text-align: right"
      :disabled="hasEmpty"
      @click="addRow"
    >
      {{ `+ 新增${props.addTitle}` }}
    </el-button>
    <el-table :data="modelValue" borderd size="small" style="width: 100%">
      <!-- 动态列 -->
      <el-table-column
        v-for="col in columns"
        :key="col.prop"
        :prop="col.prop"
        :label="col.label"
        :min-width="col.width || 140"
      >
        <template #default="{ row, $index }">
          <!-- {{ col }} -->
          <!-- 编辑态 -->
          <template v-if="row.isEdit">
            <!-- 数字 -->
            <el-input-number
              v-if="col.type === 'number'"
              v-model="row[col.prop!]"
              :min="col.min || 0"
              :precision="col.precision || 0"
              :step="col.step || 1"
              size="small"
              style="width: 100%"
            />

            <!-- 选择框 -->
            <el-select
              v-else-if="col.type === 'select'"
              v-model="row[col.prop!]"
              :multiple="col.multiple || false"
              size="small"
              style="width: 100%"
            >
              <el-option
                v-for="opt in col.options"
                :key="opt.value"
                :label="opt.label"
                :value="opt.value"
              />
            </el-select>

            <el-switch
              v-else-if="col.type === 'switch'"
              v-model="row[col.prop!]"
              inline-prompt
              active-text="启用"
              inactive-text="禁用"
              @change="toggleEnable($index)"
            />
            <!-- 默认输入框 -->
            <el-input
              v-else
              v-model="row[col.prop!]"
              :placeholder="col.placeholder || `请输入${col.label}`"
              size="small"
            />
          </template>

          <!-- 只读态 -->

          <!-- 默认渲染 -->
          <span v-else>
            <span v-if="col.type === 'switch'">
              <el-switch
                v-model="row[col.prop!]"
                inline-prompt
                active-text="启用"
                inactive-text="禁用"
                @change="toggleEnable($index)"
              />
            </span>
            <span v-else>
              {{
                col.formatter
                  ? col.formatter(row[col.prop!])
                  : col.multiple
                  ? (row[col.prop!] || []).join("、")
                  : row[col.prop!]
              }}
            </span>
          </span>
        </template>
      </el-table-column>

      <!-- 固定操作列 -->
      <el-table-column label="操作" width="180" fixed="right">
        <template #default="{ row, $index }">
          <template v-if="row.isEdit">
            <!-- 启用 / 禁用 开关 -->
            <el-button type="success" size="small" text @click="saveRow($index)"
              >保存</el-button
            >
            <el-popconfirm title="确定删除吗？" @confirm="delRow($index)">
              <template #reference>
                <el-button type="danger" size="small" text>删除</el-button>
              </template>
            </el-popconfirm>
          </template>
          <template v-else>
            <el-button type="primary" size="small" text @click="editRow($index)"
              >修改</el-button
            >
            <el-popconfirm title="确定删除吗？" @confirm="delRow($index)">
              <template #reference>
                <el-button
                  type="danger"
                  size="small"
                  :disabled="row.enable && props.switchEnabled"
                  text
                  >删除</el-button
                >
              </template>
            </el-popconfirm>
          </template>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script setup lang="ts" generic="T extends Record<string, any>">
import { ref, computed, watch } from "vue";
import { ElMessage } from "element-plus";

/* ---------- 通用列配置 ---------- */
export interface EditColumn<T = any> {
  prop: keyof T; // 字段名
  label: string; // 表头
  type?: "input" | "number" | "select" | "switch"; // 编辑时组件类型
  width?: number | string;
  min?: number;
  precision?: number;
  step?: number;
  placeholder?: string;
  options?: { label: string; value: any }[]; // select 选项
  multiple?: boolean;
  formatter?: (val: any) => string; // 只读格式化
}

/* ---------- props & emit ---------- */
interface Props<T> {
  columns: EditColumn<T>[];
  modelValue: T[];
  emptyRowFactory: () => T; // 新建空行模板
  switchEnabled?: boolean;
  addTitle: string;
}

const props = defineProps<Props<any>>();
const emit = defineEmits<{
  "update:modelValue": [rows: any[]];
  "row-delete": [rows: any[]];
}>();

const rows = ref<any[]>([...props.modelValue]);
watch(
  () => props.modelValue,
  (val) => (rows.value = [...val]),
  { deep: true }
);
/* 是否还有空行 */
const hasEmpty = computed(() =>
  rows.value.some((r) => r.isEdit && props.columns.some((c) => !r[c.prop]))
);

/* 行操作 */
function addRow() {
  if (props.switchEnabled) {
    rows.value.unshift({
      ...props.emptyRowFactory(),
      isEdit: true,
      enable: true,
    });
  } else {
    rows.value.unshift({ ...props.emptyRowFactory(), isEdit: true });
  }
  emit("update:modelValue", rows.value);
}
function editRow(index: number) {
  rows.value[index].isEdit = true;
  emit("update:modelValue", rows.value);
}
function saveRow(index: number) {
  const row = rows.value[index];
  // 简单校验：必填项非空
  for (const col of props.columns) {
    if (!row[col.prop] && col.type !== "number") {
      ElMessage.warning(`请填写${col.label}`);
      return;
    }
  }
  row.isEdit = false;
  ElMessage.success("保存成功");
}
function delRow(index: number) {
  const rowData = rows.value.splice(index, 1);
  ElMessage.success("已删除");
  emit("row-delete", rowData);
  emit("update:modelValue", rows.value);
}

function toggleEnable(index: number) {
  rows.value[index].enables == !rows.value[index].enables;
  emit("update:modelValue", rows.value);
}
</script>

<style scoped>
.edit-table {
  text-align: right;
  .el-button + .el-button {
    margin-left: 8px;
  }
}
</style>
